<?php
namespace libs\qoy\Cache;
use libs\qoy\Exception\ExceptionInternalServerError;
/**
 * CacheFile 文件缓存
 * @param array $config 初始化配置
 * @param string $config['path'] 缓存写入路径
 * @param string $config['prefix'] key前缀前缀
 */
class File implements ICache {

    protected $folder;
    protected $prefix;
    /**
     * 构造方法
     * @param type $config  初始化配置
     * @param string $config['path'] 缓存写入路径
     * @param string $config['prefix'] key前缀前缀
     */
    public function __construct(array $config) {
        $this->folder = rtrim($config['path'], '/');
        $cacheFolder = $this->createCacheFileFolder();
        if (!is_dir($cacheFolder)) {
            mkdir($cacheFolder, 0777, TRUE);
        }
        $this->prefix = isset($config['prefix']) ? $config['prefix'] : 'qoy'; 
    }
    /**
     * 
     * @see ICache->set
     */
    public function set(string $key, $value, int $expire = 600) {
        if ($key === NULL || $key === '') {
            return;
        }
        $filePath = $this->createCacheFilePath($key);
        $expireStr = sprintf('%010d', $expire + time());
        if (strlen($expireStr) > 10) {
            throw new ExceptionInternalServerError(ExceptionInternalServerError::FILE_EXPIRE_IS_TOO_LARGE);
        }
        if (!file_exists($filePath)) {
            touch($filePath);
            chmod($filePath, 0777);
        }
        file_put_contents($filePath, $expireStr . serialize($value));
    }
    /**
     * @see ICache->get
     */
    public function get(string $key) {
        $filePath = $this->createCacheFilePath($key);

        if (file_exists($filePath)) {
            $expireTime = file_get_contents($filePath, FALSE, NULL, 0, 10);

            if ($expireTime > time()) {
                return @unserialize(file_get_contents($filePath, FALSE, NULL, 10));
            }
        }

        return NULL;
    }
    /**
     * @see ICache->delete
     */
    public function delete(string $key) {
        if ($key === NULL || $key === '') {
            return;
        }

        $filePath = $this->createCacheFilePath($key);
        @unlink($filePath);
    }

    /**
     * 考虑到Linux同一目录下的文件个数限制，这里拆分成1000个文件缓存目录
     * @param string $key 缓存key
     * @return mixed 
     */
    protected function createCacheFilePath(string $key) {
        
        $folderSufix = sprintf('%03d', hexdec(substr(sha1($key), -5)) % 1000);
        $cacheFolder = $this->createCacheFileFolder() . DIRECTORY_SEPARATOR . $folderSufix;
        if (!is_dir($cacheFolder)) {
            mkdir($cacheFolder, 0777, TRUE);
        }

        return $cacheFolder . DIRECTORY_SEPARATOR . md5($key) . '.dat';
    }

    protected function createCacheFileFolder() {
        return $this->folder . DIRECTORY_SEPARATOR . 'cache';
    }
}

